package product

import (
	"bytes"
	"fmt"
	"strings"
	"vue-admin-server/global"
	"vue-admin-server/model/product"
	"vue-admin-server/model/product/response"
)

type ProductService struct{}

func (exa *ProductService) CreateExaProduct(e product.ChipSpec) (err error) {
	err = global.GVA_DB.Create(&e).Error
	return err
}

func (exa *ProductService) DeleteExaProduct(e product.ChipSpec) (err error) {
	err = global.GVA_DB.Delete(&e).Error
	return err
}

func (exa *ProductService) UpdateExaProduct(e *product.ChipSpec) (err error) {
	err = global.GVA_DB.Save(e).Error
	return err
}

func (exa *ProductService) GetExaProduct(id uint) (err error, product product.ChipSpec) {
	err = global.GVA_DB.Where("id = ?", id).First(&product).Error
	return
}

func (exa *ProductService) GetChips(p *response.ChipList) (err error) {
	sqlStr := `
SELECT 
    cs.id AS chip_id,
    cs.supplier AS supplier,
    cs.chip_no AS chip_no,
    cs.raycus_no AS raycus_no,
    cs.status AS status,
	DATE_FORMAT(cs.incoming_time, '%Y-%m') AS incoming_time,
    DATE_FORMAT(cs.incoming_time, '%Y') AS incoming_time_m,
    tr.module_type AS module_type,
    rrrr.mean_time_between_failure AS mean_time_between_failure,
    cpv_ew.typical_value AS emitter_width,
    cpv_bdp.typical_value AS beam_divergence_parallel,
    cpv_spcw.typical_value AS standard_pulse_center_wavelength
FROM
    chip_specs cs
        LEFT JOIN
    (SELECT 
        chip_id, GROUP_CONCAT(DISTINCT module_type) AS module_type
    FROM
        test_reports
    GROUP BY chip_id) AS tr ON cs.id = tr.chip_id
        LEFT JOIN
    (SELECT 
        rr.id, rr.chip_id, rr.mean_time_between_failure
    FROM
        reliability_reports rr
    RIGHT JOIN (SELECT 
        chip_id, MAX(id) AS id
    FROM
        reliability_reports
    GROUP BY chip_id) AS rrr ON rrr.id = rr.id) AS rrrr ON cs.id = rrrr.chip_id
        LEFT JOIN
    chip_parameter_values AS cpv_ew ON cpv_ew.report_id = cs.id
        AND cpv_ew.report_type = 'SPEC'
        AND cpv_ew.parameter_id = 'emitter_width'
        LEFT JOIN
    chip_parameter_values AS cpv_bdp ON cpv_bdp.report_id = cs.id
        AND cpv_bdp.report_type = 'SPEC'
        AND cpv_bdp.parameter_id = 'beam_divergence_parallel'
        LEFT JOIN
    chip_parameter_values AS cpv_spcw ON cpv_spcw.report_id = cs.id
        AND cpv_spcw.report_type = 'SPEC'
        AND cpv_spcw.parameter_id = 'standard_pulse_center_wavelength'
`

	// where
	if len(p.QueryParams) > 0 {
		var whereSqlBuf bytes.Buffer
		whereSqlBuf.WriteString("where ")
		for k, v := range p.QueryParams {
			if whereSqlBuf.Len() > len("where ") {
				whereSqlBuf.WriteString(" and ")
			}

			if k == "supplier" || k == "chip_no" || k == "raycus_no" || k == "module_type" {
				whereSqlBuf.WriteString(k + " like '%" + v + "%' ")
				continue
			}

			if k == "emitter_width" {
				whereSqlBuf.WriteString("cpv_ew.typical_value = '" + v + "' ")
				continue
			}

			if k == "beam_divergence_parallel" {
				whereSqlBuf.WriteString("cpv_bdp.typical_value = '" + v + "' ")
				continue
			}

			if k == "standard_pulse_center_wavelength" {
				whereSqlBuf.WriteString("cpv_spcw.typical_value like '%" + v + "%' ")
				//whereSqlBuf.WriteString("cpv_spcw.typical_value = '" + v + "' ")
				continue
			}

			if k == "incoming_time" {
				// v 2021-12-31T16:00:00.000Z
				split := strings.Split(v, "-")
				whereSqlBuf.WriteString("DATE_FORMAT(cs.incoming_time, '%Y') = '" + split[0] + "' ")
				continue
			}

			// k == "emitter_width" || k == "mean_time_between_failure" || k == "beam_divergence_parallel" || k == "standard_pulse_center_wavelength"
			whereSqlBuf.WriteString(fmt.Sprintf(" %v = '%v' ", k, v))
		}

		whereSql := whereSqlBuf.String()
		sqlStr = sqlStr + whereSql
	}

	sqlCountStr := fmt.Sprintf("SELECT COUNT(ccc.chip_id) FROM (%v) AS ccc", sqlStr)
	err = global.GVA_DB.Raw(sqlCountStr).Count(&p.Total).Error
	if err != nil {
		return err
	}

	limitSql := fmt.Sprintf("Limit %v, %v", (p.Page-1)*p.Limit, p.Limit)
	sqlStr = sqlStr + " Order by cs.id desc " + limitSql
	return global.GVA_DB.Raw(sqlStr).Scan(&p.Items).Error
}

func (exa *ProductService) GetChipSpec(chipIdStr string) (spec *response.ChipSpec, err error) {
	var chipSpec product.ChipSpec
	err = global.GVA_DB.First(&chipSpec, "id = ?", chipIdStr).Error
	if err != nil {
		return nil, err
	}

	spec = &response.ChipSpec{
		ChipID:              chipSpec.ID,
		Supplier:            chipSpec.Supplier,
		ChipNo:              chipSpec.ChipNo,
		RaycusNo:            chipSpec.RaycusNo,
		IncomingTime:        chipSpec.IncomingTime,
		SpecFileURI:         chipSpec.SpecFileURI,
		SpecialRequirements: chipSpec.SpecialRequirements,
		Params:              make(map[string][]response.ChipSpecParam, 0),
	}

	sqlStr := `
SELECT 
    cpv.id AS id,
    cpv.report_id AS chip_id,
    cp.item_id AS item_id,
    cp.item AS item,
    cp.parameter_id AS parameter_id,
    cp.parameter AS parameter,
    cp.symbol AS symbol,
    cp.unit AS unit,
    cpv.test_condition AS test_condition,
    cpv.min_value AS min_value,
    cpv.max_value AS max_value,
    cpv.typical_value AS typical_value
FROM
    chip_parameter_values cpv
        LEFT JOIN
    chip_parameters cp ON cpv.item_id = cp.item_id
        AND cpv.parameter_id = cp.parameter_id
WHERE
    report_id = %v AND report_type = 'SPEC'
ORDER BY id

`
	params := make([]response.ChipSpecParam, 0)
	err = global.GVA_DB.Raw(fmt.Sprintf(sqlStr, chipIdStr)).Find(&params).Error
	if err != nil {
		return spec, nil
	}

	for _, p := range params {
		if p.ItemID == "photoelectric_parameter" {
			spec.Params["photoelectric_parameter"] = append(spec.Params["photoelectric_parameter"], p)
		} else if p.ItemID == "structure_parameter" {
			spec.Params["structure_parameter"] = append(spec.Params["structure_parameter"], p)
		}
	}
	return spec, nil
}
